package com.otp.webapp.action;

import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

import org.appfuse.Constants;
import org.appfuse.model.Organization;
import org.appfuse.model.Role;
import org.appfuse.model.User;
import org.appfuse.service.RoleManager;
import org.appfuse.service.UserExistsException;
import org.appfuse.util.ConvertUtil;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.mail.MailException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import com.otp.exceptions.EmailExistsException;
import com.otp.service.instance.TestInstanceManager;
import com.otp.service.instance.User1Manager;
import com.otp.service.util.EncryptString;
import com.otp.webapp.util.RequestUtil;


public class UserForm extends BasePage implements Serializable {
	private static final long serialVersionUID = -1141119853856863204L;

	private RoleManager roleManager;
	private TestInstanceManager testInstanceManager;
	private User1Manager user1Manager;

	private String id;
	private User user = new User();
	@SuppressWarnings("unused")
	private User loggedInUser;
	private String userOrgStr = null;
	private String[] userRoles;
	private Map<String, String> availableRoles;

	boolean adminUser = false;
	boolean superAdminUser = false;
	boolean editOrg = false;



	public User1Manager getUser1Manager() {
		return user1Manager;
	}

	public void setUser1Manager(User1Manager user1Manager) {
		this.user1Manager = user1Manager;
	}

	public void setTestInstanceManager(
			@Qualifier("testInstanceManager") TestInstanceManager testInstancesManager) {
		this.testInstanceManager = testInstancesManager;
	}

	public boolean isEditOrg() {
		return !superAdminUser;
	}

	public void setEditOrg(boolean editOrg) {
		this.editOrg = editOrg;
	}

	public void setId(String id) {
		this.id = id;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public void setRoleManager(RoleManager roleManager) {
		this.roleManager = roleManager;
	}

	public User getLoggedInUser() {
		return loggedInUser = getLoggedUser();
	}

	public void setLoggedInUser(User logUser) {
		this.loggedInUser = getLoggedUser();
	}


	public String add() {
		user = new User();
		user.setEnabled(true);
		user.addRole(new Role(Constants.USER_ROLE));
		return "editProfile";
	}

	public String cancel() {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'cancel' method");
		}
		return "mainMenu";
	}

	public String initUser() {
		// if a user's id is passed in
		if (id != null) {

			if (getLoggedUser() != null
					&& getLoggedUser().getId().toString().equals(id)) {
				user = getLoggedUser();
			} else {
				log.debug("Editing user, id is: " + id);
				// lookup the user using that id
				user = userManager.getUser(id);
			}

		} else {
			user = getLoggedUser();
		}

		if (user.getUsername() != null) {
			user.setConfirmPassword(user.getPassword());
			if (isRememberMe()) {
				// if user logged in with remember me, display a warning that
				// they can't change passwords
				log.debug("checking for remember me login...");
				log.trace("User '" + user.getUsername()
						+ "' logged in with cookie");
				addMessage("userProfile.cookieLogin");
			}
		}

		return "editProfile";
	}

	/**
	 * Convenience method for view templates to check if the user is logged in
	 * with RememberMe (cookies).
	 * 
	 * @return true/false - false if user interactively logged in.
	 */
	public boolean isRememberMe() {
		if (user != null && user.getId() == null)
			return false; // check for add()

		AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
		SecurityContext ctx = SecurityContextHolder.getContext();

		if (ctx != null) {
			Authentication auth = ctx.getAuthentication();
			return resolver.isRememberMe(auth);
		}
		return false;
	}

	public String save() throws IOException {
		// workaround for plain ol' HTML input tags that don't seem to set
		// properties on the managed bean

		// check space in username
		Pattern pattern = Pattern.compile("\\s");
		Matcher matcher = pattern.matcher(user.getUsername());
		boolean found = matcher.find();

		if (found) {
			addError("Space is not allowed in username");
			return null;
		}

		//UPDATE roles
		setUserRoles(getRequest().getParameterValues("userForm:userRoles"));
		for (int i = 0; (userRoles != null) && (i < userRoles.length); i++) 
			user.addRole(roleManager.getRole(userRoles[i]));

		//UPDATE orgs
		//If org parameter is set, update user orgs
		//else if user.org is not null do nothing
		//else get org from logged-in user
		String org = userOrgStr;
		if(org==null||org.isEmpty()) org = getRequest().getParameter("userForm:userOrg");
		if(org!=null&&!org.isEmpty()){
			Organization orgInDB = testInstanceManager.getOrgByName(org);
			Organization newOrg = new Organization();
			newOrg.setObjectId(orgInDB.getObjectId());
			newOrg.setOrganizationName(orgInDB.getOrganizationName());
			newOrg.setOrganizationDescription(orgInDB.getOrganizationDescription());
			user.setOrgs(newOrg);
		}
		else if (user.getOrgs()==null||user.getOrgs()==null){
			org = getLoggedUserOrganization().getOrganizationName();
			Organization orgInDB = testInstanceManager.getOrgByName(org);
			Organization newOrg = new Organization();
			newOrg.setObjectId(orgInDB.getObjectId());
			newOrg.setOrganizationName(orgInDB.getOrganizationName());
			newOrg.setOrganizationDescription(orgInDB.getOrganizationDescription());
			user.setOrgs(newOrg);
		}

		//UPDATE PASSWORD
		//Encrypt if unencrypted
		if (user.getPassword().length() < 40) {
			user.setPassword(EncryptString.encrypt(user.getPassword()));
			user.setConfirmPassword(EncryptString.encrypt(user.getPassword()));
		}

		//UPDATE DATE OF BIRTH
		String dateStr = getRequest().getParameter("dateOfBirth");
		SimpleDateFormat f = new SimpleDateFormat("MM/dd/yyyy");
		Date birthDate = null;		
		try{
			birthDate = f.parse(dateStr);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if (birthDate != null) user.setDateOfBirth(birthDate);


		try {
			if (user.getId() == null || user.getId() == 0) user1Manager.addUser(user);
			else user1Manager.updateUser(user);		
		} 
		catch (AccessDeniedException ade) {
			// thrown by UserSecurityAdvice configured in aop:advisor
			// userManagerSecurity
			log.warn(ade.getMessage());
			getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
			return null;
		} 
		catch (UserExistsException e) {
			addMessage("errors.existing.user", new Object[]{user.getUsername(), user.getEmail()});
			// redisplay the unencrypted passwords
			user.setPassword(user.getConfirmPassword());
			return null;
		} 
		catch (EmailExistsException e) {
			addMessage("errors.existing.email", new Object[]{user.getEmail()});
			// redisplay the unencrypted passwords
			user.setPassword(user.getConfirmPassword());
			return null;
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (!"list".equals(getParameter("from"))) {
			// add success messages
			addMessage("user.saved");

			// return to main Menu
			return "mainMenu";
		} else {
			// add success messages
			if ("".equals(getParameter("userForm:version"))) {
				addMessage("user.added", user.getFullName());

				try {
					sendUserMessage(
							user,
							//getText("newuser.email.message", user.getFullName()),
							null,
							RequestUtil.getAppURL(getRequest()));
				} catch (MailException me) {
					addError(me.getCause().getLocalizedMessage());
				}

				return "list"; // return to list screen
			} else {
				addMessage("user.updated.byAdmin", user.getFullName());
				return "editProfile"; // return to current page
			}
		}
	}

	public String delete() {
		userManager.removeUser(getUser().getId().toString());
		addMessage("user.deleted", getUser().getFullName());

		return "list";
	}

	/**
	 * Convenience method to determine if the user came from the list screen
	 * 
	 * @return String
	 */
	public String getFrom() {/*
	 * System.out.println("Get form="+getParameter(
	 * "editUser:add")); if ((id != null) ||
	 * (getParameter("editUser:add") != null) ||
	 * ("list".equals(getParameter("from")))) { return
	 * "list"; }
	 * 
	 * if(id==null) edit();
	 * 
	 * return "list";
	 */
		return getParameter("from");
	}

	public String getUserOrgStr() {
		if(userOrgStr!=null&&!userOrgStr.isEmpty()) return userOrgStr;
		if(user!=null && user.getOrgs()!=null) return userOrgStr=user.getOrgs().getOrganizationName();
		return userOrgStr=getLoggedUserOrganization().getOrganizationName();
	}

	public void setUserOrg(String userOrgStr) {
		this.userOrgStr = userOrgStr;
	}

	// Form Controls ==========================================================
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Map<String, String> getAvailableRoles() {
		if (availableRoles == null) {
			List roles = (List) getServletContext().getAttribute(
					Constants.AVAILABLE_ROLES);

			availableRoles = ConvertUtil.convertListToMap(roles);
			if (!isSuperAdminUser() && availableRoles != null) {
				availableRoles.remove("ROLE_SUPER_ADMIN");
			}
		}

		return availableRoles;
	}

	public String[] getUserRoles() {
		userRoles = new String[user.getRoles().size()];

		int i = 0;

		if (userRoles.length > 0) {
			for (Role role : user.getRoles()) {
				userRoles[i] = role.getName();
				i++;
			}
		}

		return userRoles;
	}

	public void setUserRoles(String[] userRoles) {
		this.userRoles = userRoles;
	}

	public String getCountry() {
		return getUser().getAddress().getCountry();
	}

	// for some reason, the country drop-down won't do
	// getUser().getAddress().setCountry(value)
	public void setCountry(String country) {
		getUser().getAddress().setCountry(country);
	}

	public String getForm() {
		User currentUser = userManager.getUserByUsername(getRequest()
				.getRemoteUser());

		for (Role role : currentUser.getRoles()) {
			if (role.getName().equals("ROLE_ADMIN")) {
				adminUser = true;
			}
			if (role.getName().equals("ROLE_SUPER_ADMIN")) {
				superAdminUser = true;
			}
		}
		return null;
	}

	public void setForm(String form) {

	}

	@SuppressWarnings("unused")
	private User copyUser(User u) {

		User copiedUser = new User();

		copiedUser.setAccountExpired(u.isAccountExpired());
		copiedUser.setAccountLocked(u.isAccountLocked());
		copiedUser.setAddress(u.getAddress());
		copiedUser.setConfirmPassword(u.getConfirmPassword());
		copiedUser.setCredentialsExpired(u.isCredentialsExpired());
		copiedUser.setEmail(u.getEmail());
		copiedUser.setEnabled(u.isEnabled());
		copiedUser.setFirstName(u.getFirstName());
		copiedUser.setId(u.getId());
		copiedUser.setLastName(u.getLastName());
		copiedUser.setPassword(u.getPassword());
		copiedUser.setPhoneNumber(u.getPhoneNumber());
		copiedUser.setVersion(u.getVersion());
		copiedUser.setUsername(u.getUsername());
		copiedUser.setWebsite(u.getWebsite());

		Set<Role> newRoles = new HashSet<Role>();
		if (u.getRoles() != null && u.getRoles().size() > 0) {
			for (Role r : u.getRoles()) {
				newRoles.add(r);
			}
		}
		copiedUser.setRoles(newRoles);

		Organization newOrg = new Organization();
		newOrg.setObjectId(u.getOrgs().getObjectId());
		newOrg.setOrganizationName(u.getOrgs().getOrganizationName());
		newOrg.setOrganizationDescription(u.getOrgs()
				.getOrganizationDescription());
		copiedUser.setOrgs(newOrg);

		return copiedUser;
	}

}